package com.cin.cma.common.signature;

import cn.hutool.crypto.digest.DigestUtil;
import com.alibaba.fastjson2.JSONArray;
import com.alibaba.fastjson2.JSONObject;
import com.alibaba.fastjson2.JSONWriter;
import com.cin.cma.common.constant.HeaderConstant;
import com.cin.cma.common.enums.SignTypeEnum;
import com.cin.cma.common.exception.UserFriendlyException;

import java.math.BigDecimal;
import java.text.DecimalFormat;
import java.util.Map;
import java.util.SortedMap;
import java.util.TreeMap;


public class SignatureHelper {

    /**
     * 签名
     *
     * @param apiKey    系统分配
     * @param apiSecret 系统分配
     * @param apiType   签名类型（MD5|SHA256）
     * @param timestamp 时间戳
     * @param nonce     随机数
     * @param params    参数
     * @return 签名
     * @throws UserFriendlyException 异常提醒
     */
    public static String build(String apiKey, String apiSecret, String apiType, String timestamp, String nonce, String params) throws UserFriendlyException {
        SortedMap<String, Object> formBody = new TreeMap<>();
        if (params != null) {
            formBody = JSONObject.parseObject(params, SortedMap.class);
        }
        return build(apiKey, apiSecret, apiType, timestamp, nonce, formBody);
    }

    /**
     * 签名
     *
     * @param apiKey    系统分配
     * @param apiSecret 系统分配
     * @param apiType   签名类型（MD5|SHA256）
     * @param timestamp 时间戳
     * @param nonce     随机数
     * @param formBody  参数
     * @return 签名
     * @throws UserFriendlyException 异常提醒
     */
    public static String build(String apiKey, String apiSecret, String apiType, String timestamp, String nonce, SortedMap<String, Object> formBody) throws UserFriendlyException {
        StringBuilder signatureSb = new StringBuilder();
        signatureSb.append(HeaderConstant.API_KEY).append("=").append(apiKey).append("&");
        signatureSb.append(HeaderConstant.API_TYPE).append("=").append(apiType).append("&");
        signatureSb.append(HeaderConstant.TIMESTAMP).append("=").append(timestamp).append("&");
        signatureSb.append(HeaderConstant.NONCE).append("=").append(nonce).append("&");
        for (Map.Entry map : formBody.entrySet()) {
            if (map.getValue() == null) {
                continue;
            }
            String value;
            if (map.getValue() instanceof String) {
                value = (String) map.getValue();
            } else if (map.getValue() instanceof Boolean) {
                value = map.getValue().toString().toLowerCase();
            } else if (map.getValue() instanceof BigDecimal) {
                DecimalFormat df = new DecimalFormat("0.00");
                value = df.format(map.getValue());
            } else if (map.getValue() instanceof JSONArray || map.getValue() instanceof JSONObject || map.getValue() instanceof JSONArray || map.getValue() instanceof JSONObject) {
                if (map.getValue() instanceof JSONArray) {
                    if (((JSONArray) map.getValue()).isEmpty()) {
                        continue;
                    }
                } else if (map.getValue() instanceof JSONArray) {
                    if (((JSONArray) map.getValue()).isEmpty()) {
                        continue;
                    }
                }
                //加密时保留原有的对象值，不要去除空字符串和Null
                value = JSONObject.toJSONString(map.getValue(), JSONWriter.Feature.WriteMapNullValue);
            } else {
                value = map.getValue().toString();
            }
            if (value != null && !value.isEmpty()) {
                signatureSb.append(map.getKey());
                signatureSb.append("=");
                signatureSb.append(value);
                signatureSb.append("&");
            }
        }
        signatureSb.append(HeaderConstant.API_SECRET);
        signatureSb.append("=");
        signatureSb.append(apiSecret);
        String sysSignature = signatureSb.toString();
        SignTypeEnum signType = SignTypeEnum.valueOf(apiType);

        switch (signType) {
            case MD5:
                sysSignature = DigestUtil.md5Hex(sysSignature).toUpperCase();
                break;
            case SHA256:
                sysSignature = DigestUtil.sha256Hex(sysSignature).toUpperCase();
                break;
        }

        return sysSignature;
    }
}
